package com.lab.idea.bl.controller;

import cn.hutool.core.codec.Base64Encoder;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.*;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.GlobalThreadPool;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.system.SystemUtil;
import com.lab.idea.bl.entity.ExcelTemplate;
import com.lab.idea.bl.service.ExcelTemplateService;
import com.lab.idea.bl.util.BlExcelReadUtil;
import com.lab.idea.bl.vo.QueryData;
import com.lab.idea.common.Response;
import com.lab.idea.common.exception.LabException;
import com.lab.idea.module.report.ReportHelper;
import com.lab.idea.module.report.ReportPlugin;
import com.lab.idea.module.report.ReportResponse;
import com.lab.idea.module.report.ReportTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import com.lab.idea.mybatis.controller.LabController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;

/**
 * <p>
 * excel模板 前端控制器
 * </p>
 *
 * @author lab
 * @since 2023-11-06
 */
@Slf4j
@RestController
@RequestMapping("/excelTemplate")
public class ExcelTemplateController extends LabController<ExcelTemplateService, ExcelTemplate> {

    @Value("${home}")
    private String home;

    @PostMapping("/upload/{excelId}")
    public Response<String> upload(@PathVariable String excelId,@RequestBody MultipartFile file){
        try {
            String suffix = FileUtil.getSuffix(file.getOriginalFilename());
            String path = String.format("%s%s%s",home, SystemUtil.getOsInfo().getFileSeparator(),file.getOriginalFilename());
            if (FileUtil.isFile(path)) {
                String fileName = String.format("%s.%s",DateUtil.format(DateUtil.date(), DatePattern.CHINESE_DATE_TIME_FORMAT),suffix);
                FileUtil.move(FileUtil.file(path),FileUtil.file(String.format("%s%s%s",home, SystemUtil.getOsInfo().getFileSeparator(),fileName)),true);
            }
            File[] files = FileUtil.ls(home);
            List<JSONObject> treeJson = new ArrayList<>();
            for (File file1 : files) {
                if (!FileUtil.isFile(file1)
                        || !StrUtil.equals("xlsx",FileUtil.getSuffix(file1))
                        || !StrUtil.equals("xlsm",FileUtil.getSuffix(file1))
                        || !StrUtil.equals("docx",FileUtil.getSuffix(file1))) {
                    continue;
                }
                try {
                    DateTime dateTime = DateUtil.parse(FileUtil.mainName(file1),DatePattern.CHINESE_DATE_TIME_FORMAT);
                    JSONObject object = new JSONObject();

                    long day = DateUtil.between(dateTime, DateUtil.date(), DateUnit.HOUR);
                    object.set("dateTime",dateTime).set("day",day).set("path",file1.getAbsolutePath());
                    treeJson.add(object);
                }catch (Exception e){
                    log.error("忽略excel{}",file1.getName());
                }
            }
            if (treeJson.size() > 10) {
                List<JSONObject> list = CollUtil.sortByProperty(treeJson, "day");
                for (int i = 10; i < list.size(); i++) {
                    JSONObject object = list.get(i);
                    FileUtil.del(object.getStr("path"));
                }
            }
            FileUtil.writeBytes(file.getBytes(),path);
            ExcelTemplate excelTemplate = service.getById(excelId);
            if (StrUtil.equalsIgnoreCase(suffix,"xlsx") || StrUtil.equalsIgnoreCase(suffix,"xlsm")) {
                excelTemplate.setExcelPath(path);
            } else {
                excelTemplate.setDocxPath(path);
            }
            save(excelTemplate);
            return Response.success(path);
        }catch (Exception e){
            throw new LabException("模板上传异常",e);
        }
    }

    @GetMapping("/init/{excelId}")
    public Response<Boolean> init(@PathVariable String excelId,@RequestParam(value = "sheetId",required = false)String sheetId){
        service.init(excelId, StrUtil.split(sheetId,"@"));
        return Response.success(true);
    }

    @PostMapping("/queryData/{outId}")
    public Response<QueryData> queryData(@PathVariable String outId, @RequestBody JSONObject args){
        return Response.success(service.queryData(outId,args));
    }

    @PostMapping("/exportExcel/{outId}")
    public Response<String> exportExcel(@PathVariable String outId, @RequestBody Map<String,String> args){
        return Response.success(service.exportExcel(outId,new JSONObject(args)));
    }

    private Map<String, List<JSONObject>> readExcelFile(MultipartFile file){
        TimeInterval timeInterval = new TimeInterval();
        try {
            log.info("excel读取开始:{}",file.getOriginalFilename());
            return BlExcelReadUtil.readExcelMap(file.getBytes());
        }catch (Exception e){
            log.error("文件{}读取异常",file.getOriginalFilename(),e);
        } finally {
            log.info("excel读取完成:{} 耗时:{}",file.getOriginalFilename(),timeInterval.intervalRestart());
        }
        return new HashMap<>();
    }
    @PostMapping("/createReport/{excelId}")
    public Response<JSONObject> createReport(@PathVariable String excelId,@RequestBody MultipartFile[] files,@RequestParam Map<String, String> args){
        try {
            if (files.length < 1) {
                throw new LabException("请选择数据源文件");
            }
            log.info("报告生成接受文件数量:{}",files.length);
            ExcelTemplate excelTemplate = service.getById(excelId);
            ReportTemplate template = new ReportTemplate().setPlugins(CollUtil.newArrayList());
            template.setTemplateName(FileUtil.getName(excelTemplate.getDocxPath()));
            JSONObject env = new JSONObject(args);
            List<MultipartFile> excels = new ArrayList<>();
            for (MultipartFile file : files) {
                String suffix = FileUtil.extName(file.getOriginalFilename());
                if (StrUtil.equalsIgnoreCase("docx",suffix)) {
                    // 模板
                    template.setTemplateName(file.getOriginalFilename()).setBytes(file.getBytes());
                } else {
                    excels.add(file);
                }
            }
            Map<String,Map<String, List<JSONObject>>> excelMap = new ConcurrentHashMap<>();
            CountDownLatch downLatch = new CountDownLatch(excels.size());
            for (MultipartFile file : excels) {
                GlobalThreadPool.execute(() -> {
                    try {
                        String mainName = FileUtil.mainName(file.getOriginalFilename());
                        excelMap.put(mainName,readExcelFile(file));
                    } finally {
                        downLatch.countDown();
                    }
                });
            }
            downLatch.await();
            for (Map.Entry<String, Map<String, List<JSONObject>>> mapEntry : excelMap.entrySet()) {
                String mainName = mapEntry.getKey();
                Map<String, List<JSONObject>> valueMap = mapEntry.getValue();
                for (Map.Entry<String, List<JSONObject>> entry : valueMap.entrySet()) {
                    List<JSONObject> list = entry.getValue();
                    env.set(entry.getKey(),list);
                    template.getPlugins().add(new ReportPlugin().setSourceProp(entry.getKey()).setPluginProp("LoopRowTableRenderPolicy"));
                    if (StrUtil.equals("0",entry.getKey())) {
                        // 添加文件名属性为第0个sheet的值
                        env.set(mainName,list);
                        template.getPlugins().add(new ReportPlugin().setSourceProp(mainName).setPluginProp("LoopRowTableRenderPolicy"));
                        if (StrUtil.equals("质控报告字段",mainName) || StrUtil.equals("检测报告字段",mainName)) {
                            // 增加excel变量
                            for (JSONObject entries : list) {
                                String prop = entries.getStr("c2", StrUtil.EMPTY);
                                String value = entries.getStr("c4", StrUtil.EMPTY);
                                if (StrUtil.isBlankIfStr(prop)) {
                                    continue;
                                }
                                env.set(prop,value);
                            }
                        }
                    }

                }
            }
            if (template.getBytes() == null) {
                if (StrUtil.isBlankIfStr(excelTemplate.getDocxPath())) {
                    throw new LabException("未上传docx模板");
                }
                template.setBytes(FileUtil.readBytes(excelTemplate.getDocxPath()));
            }
            log.info("报告生成开始:{}",files.length);
            ReportResponse response = ReportHelper.createReport(template, env);
            JSONObject data = new JSONObject().set("base64", Base64Encoder.encode(response.getBytes()));
            data.set("name", String.format("%s.docx",env.getStr("reportNo",DateUtil.today())));
            return Response.success(data);
        }catch (Exception e){
            throw new LabException("报告生成异常",e);
        }
    }
}
